package {
	
	import flash.utils.Timer;
	import flash.utils.setTimeout;
	import flash.utils.getTimer;
	import flash.events.Event;
	import flash.events.ProgressEvent;
    import flash.net.Socket;
    import flash.utils.ByteArray;
	import flash.events.SecurityErrorEvent;
	import flash.events.IOErrorEvent;
	import flash.utils.Endian;

	import my1flex;
	
	import mx.controls.Alert;

	public class NetProv {
				
		   public var soc:Socket = new Socket();
		   private var iTim:Timer;
		   private var stateChange:Function;
		   private var fTimeoutIn:Function;
		   private var fRequestContent:Function;
		   private var numRequest;
		   
		   public static var ON_CONNECT = 1;
		   public static var ON_CLOSE = 2;
		   public static var ON_ERROR = 3;
		   public static var ON_DATA = 4;
		   public static var ON_DATA_END = 5;
		   public static var ON_TIMEOUT = 6;
		   public static var ON_DISCONNECT = 7;
		   public static var ON_START_SEND = 8;
		   public static var ON_ERROR_CRC = 9;
		   
		   public var timConnectApp:int;
		   [Bindable] public var dataTrafficIn:uint = 0;
		   [Bindable] public var dataTrafficOut:uint = 0;
		   [Bindable] public var is_abort:Boolean;
		   private var is_server;
		   
		   public var requestCache = [];
		   
		   
		   //*****formPack
		   public var nPack = 0;
		   public var scheme;
		   public var charSet = 'windows-1251';//'cp866'; //'utf-8'
		   public var fLog:Function;
		   private var curonData:Function;
		   public var nStructForse = 0;
		   
		   //*****server
		   public var retSoc:Socket = new Socket();
		   public var dataServ:ByteArray = new ByteArray();
		   private var oldCommand; 
		   
		   
		   
		   //********
		   
		   
			
			function NetProv(stateChange_:Function, is_server = null, fLog_ = null){
				
				fLog = fLog_;
				stateChange = stateChange_;
				initSoc(is_server);
				dataServ.endian = Endian.LITTLE_ENDIAN;
			}
			
			private function initSoc(is_server_){
				is_server = is_server_;
				soc.addEventListener(Event.CONNECT, onConnect );
		        soc.addEventListener(Event.CLOSE, function(e){ stateChange(ON_CLOSE);});
		        soc.addEventListener(IOErrorEvent.IO_ERROR, function(e){ soc.close(); stateChange(ON_ERROR, e.text);   });
				soc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function(e){soc.close();  stateChange(ON_ERROR, e.text);  });
				soc.addEventListener(ProgressEvent.SOCKET_DATA, onSocketDataGlob);
				if (is_server)
					soc.addEventListener(ProgressEvent.SOCKET_DATA, onSocketDataServer);
				
					
				
			}
			
			
			//*****************************************
			
			
			public function sendBuf(buf:ByteArray, fWaitRecive:Function = null, waitRecive = null, 
									fTimeOut = null){
					

					
					abort();
					is_abort = false;			
					fTimeoutIn = null;
					waitRecive = waitRecive || def.WHIT_RECIVE;
					/*
					//test garb
					if (is_server){
						var aa:ByteArray = new ByteArray();
						aa.writeBytes(buf);
						aa.writeByte(0x45);
						aa.writeByte(0x45);
						aa.writeInt(0x45);
						aa.writeInt(0x45);
						aa.writeInt(0x45);
						aa.writeInt(0x45);
						soc.writeBytes(aa);
					} else
					*/
					soc.writeBytes(buf);
					
					dataTrafficOut += buf.length;
					soc.flush();
								
					fTimeoutIn = fTimeoutIn || fTimeOut;
					
					//fRequestContent = function() {sendBuf(buf, fWaitRecive, waitRecive, fTimeOut, numRequest);  };
									
					
					stateChange(ON_START_SEND);
					
					if (!is_server){
						//tim
						iTim = new Timer(waitRecive, 1);
						iTim.addEventListener("timer", timOver);  
						iTim.start();
					}
							
							
							
					if (fWaitRecive){
						
							//soc fun
							var data:ByteArray = new ByteArray(); 
							data.endian = Endian.LITTLE_ENDIAN;
							
							var sizePack;
							var startPos;
							var isText;
							
							
							var onData = function(e:ProgressEvent){
									
									/*
									if (is_abort){
										soc.removeEventListener(ProgressEvent.SOCKET_DATA, onData);
										if (iTim) iTim.stop();
										return 0;	
									}
									*/
									
									soc.readBytes(data, data.length,  soc.bytesAvailable);
									
									if (dataServ.bytesAvailable > def.MAX_BYTES_REC) dataServ = new ByteArray();
									
								 	//Alert.show(data.toString());
									
									
									while (data.bytesAvailable >= 6 && !sizePack){    
											if ((data.readUnsignedByte() == 0x80) && 
												(data.readUnsignedByte() == 0x80) &&
												(data.readUnsignedByte() == 0x80)) {  
													            
												data.position += 1;
												sizePack = data.readUnsignedShort();
												startPos = data.position - 6; 
											} 
												   
									}
									
									
									if (!sizePack) isText = data.toString().match(/[\r\n]+$/);
								
									
									if ((isText && data.toString().match(/[\r\n]+$/)) ||  (sizePack && data.bytesAvailable >= sizePack - 6)){
										
										soc.removeEventListener(ProgressEvent.SOCKET_DATA, onData);	
										//Alert.show(data.toString());
										var proto = isText ? def.PROTO_TEXT : def.PROTO_BIN;
										stateChange(ON_DATA_END);
										//data.position = isText ? 0 : startPos;
										if (!isText){
											var to:ByteArray = new ByteArray();
											to.endian = Endian.LITTLE_ENDIAN;
											to.writeBytes(data, startPos,  sizePack);
											data = to;
											//Alert.show(data.position + '\n' + my1flex.dumpa(data));
										}
										data.position = 0;
										//Alert.show(fWaitRecive + '' + my1flex.dumpa(data) + ' ' + proto);
										is_abort = true;
										fWaitRecive(data, proto);
										iTim.stop();
										
									}
							};
							soc.addEventListener(ProgressEvent.SOCKET_DATA, onData);
							curonData = onData;
							
					}
					
			}
		
			
			
			
			
		  	public function sendStr(s:String, preExit:RegExp = null, 
		  							 fWaitRecive:Function = null, waitRecive = null, 
		  							 fTimeOut = null, countRequest = null) {
		  			
		  			//send(b, preExit, fWaitRecive, waitRecive, fTimeOut);
		  			
					waitRecive = waitRecive || def.WHIT_RECIVE;
					abort();  
					
					is_abort = false;
					fTimeoutIn = null;
					numRequest = countRequest == null ? def.COUNT_REQUEST_IF_NO_ANSWER : countRequest;
					fRequestContent = function() {sendStr(s, preExit, fWaitRecive, waitRecive, fTimeOut, numRequest);  };
					soc.writeMultiByte(s, charSet);
					soc.flush();
					fTimeoutIn = fTimeoutIn || fTimeOut;
					var is_ok = s.match(/\nOK\r\n/);
					fLog((is_server ? '' : '<--' ) + s, null, !is_ok, 2, is_ok);
					
					
					
						
					stateChange(ON_START_SEND);
							
					if (!is_server){
						//tim
						iTim = new Timer(waitRecive, 1);
						iTim.addEventListener("timer", timOver);
						iTim.start();
					}
							

							
					if (fWaitRecive){
							//soc fun
							var buf:ByteArray = new ByteArray();
														
							var onData = function(e:ProgressEvent){
								
								//Alert.show(is_abort);
								soc.readBytes(buf, buf.length,  soc.bytesAvailable);
								
								//var is_bin = (buf.bytesAvailable > 4 && (buf.readUnsignedShort() == 0x8080) && (buf.readUnsignedByte() == 0x80));
								
								while (buf.bytesAvailable > 3 && !is_bin)    
									var is_bin = ((buf.readUnsignedByte() == 0x80) && 
												  (buf.readUnsignedByte() == 0x80) &&
												  (buf.readUnsignedByte() == 0x80));   
																						
																										            
								//Alert.show(is_bin + '\n' + my1flex.dumpa(buf));
								if (buf.length && ( (preExit && buf.readUTFBytes(buf.bytesAvailable).match(preExit) || !preExit))){
									soc.removeEventListener(ProgressEvent.SOCKET_DATA, onData);	
									//Alert.show(buf.toString());
									//buf.position = 0;
									fLog('--> ' + (is_bin ? my1flex.dumpa(buf) :  getStrFromBuf(buf)));
									stateChange(ON_DATA_END);
									buf.position = 0;
									fWaitRecive(buf);
									iTim.stop();
									is_abort = true;
								}
							};
							soc.addEventListener(ProgressEvent.SOCKET_DATA, onData);	
							curonData = onData;
			}
					
		  	}

			
			
			public function abort(){
				
					is_abort = true;
					//fRequestContent = null;
					if (curonData)	
						soc.removeEventListener(ProgressEvent.SOCKET_DATA, curonData);
					if (iTim) iTim.stop();
								
			}
			
		
			//*******************************events
			
			private function timOver(e){
				
					/*if (curonData)	
						soc.removeEventListener(ProgressEvent.SOCKET_DATA, curonData);
					if (iTim) iTim.stop();
					*/
					
					//Alert.show(numRequest+'___' + fRequestContent);
					if (!is_abort){
							abort();
							stateChange(ON_TIMEOUT);
							if (fRequestContent && numRequest--){ 
								 fRequestContent();
							}  else if (fTimeoutIn){
											fTimeoutIn(e);
									}
					}
					
						
			}
			
			public function onSocketDataGlob(e:ProgressEvent ){

				
				stateChange(ON_DATA);
				dataTrafficIn += soc.bytesAvailable;
				 		
			}
			
			
			private var aa = 3;
			
			public function onSocketDataServer(e:ProgressEvent){

							//var dataServ:ByteArray = new ByteArray(); 
							//dataServ.endian = Endian.LITTLE_ENDIAN;
							
							var sizePack;
							var startPos; 
							var isText;
								
								
											
							//soc.readBytes(dataServ, dataServ.length, soc.bytesAvailable);
							e.currentTarget.readBytes(dataServ, dataServ.length, e.bytesLoaded);
							
							//Alert.show(my1flex.dumpa(dataServ));
							
							//soc.readBytes(dataServ);
							
							//Alert.show(dataServ.toString());
							
							if (dataServ.bytesAvailable > def.MAX_BYTES_REC) dataServ = new ByteArray(); 
							

							while (dataServ.bytesAvailable >= 6 && !sizePack) {
								if ((dataServ.readUnsignedByte() == 0x80) && 
									(dataServ.readUnsignedByte() == 0x80) &&
									(dataServ.readUnsignedByte() == 0x80)) {
										              
									dataServ.position += 1;
									sizePack = dataServ.readUnsignedShort();
									startPos = dataServ.position - 6; 
								} 
									
							}
							
							//Alert.show('dataServ.bytesAvailable='+dataServ.bytesAvailable+'startPos_'+startPos+'_ len__'+ sizePack +'\n' + my1flex.dumpa(dataServ) );
							
							if (!sizePack) isText = dataServ.toString().match(/[\r\n]+$/);   					
							
													
							if (isText || (sizePack && dataServ.bytesAvailable >= sizePack - 6)) {
								//var isLua = ????
								var res;
								
								if (isText){
									//Alert.show(my1flex.dumpa(dataServ));  
									//Alert.show((e.currentTarget == retSoc ? oldCommand : ''));
									//var inCom = dataServ.toString().match(/[^\r\n]*/);  //берем тока одну строку
									
									//var inCom = dataServ.toString();
									//dataServ.position = 0;
									//var inCom = dataServ.readMultiByte(dataServ.bytesAvailable, charSet);
									
									var inCom = getStrFromBuf(dataServ);
									
									res = extractTextPack(inCom, (e.currentTarget == retSoc ? oldCommand : '')); 
									//if (e.currentTarget == soc) oldCommand = res.commands[0][0];  
									if (e.currentTarget == soc) oldCommand = inCom.match(/[^\r\n]+/g);
									res.proto = def.PROTO_TEXT; 
									
									//if (e.currentTarget == retSoc) Alert.show(oldCommand+'____++');
									//if (e.currentTarget == retSoc) Alert.show(oldCommand);
									//my1flex.dumpl(res, '111111111111111');
									//res.type = dataServ.toString().match(/\?$/gm) ? 1 : 3;
									
									//if (res.type < 100){		
									try{
										var ind = getBinOnText(inCom, (inCom.match(/\?h?$/) ? 1 : 3), (e.currentTarget == retSoc ? oldCommand : ''));
									}catch(e) {} 
										//my1flex.dumpl(ind, 'ww');
										var dd = ind ? my1flex.dumpa(ind) : false;
									//}
									fLog({text : inCom, bin : dd ? dd : 'не возможно перевести в бинарный вид'}, null, true);
	       							
								} else {
									
									//Alert.show('startPos_'+startPos+'___'+my1flex.dumpa(dataServ));
						 			var to:ByteArray = new ByteArray();
									to.endian = Endian.LITTLE_ENDIAN;
									to.writeBytes(dataServ, startPos,  sizePack);
									
									dataServ = to;
									dataServ.position = 0;
									
									//dataServ.position = startPos;
									res = extractPack(dataServ);
									//my1flex.dumpl(res, 'xxxxxxxxx');
									res.proto = def.PROTO_BIN; 
									
									//fLog('--> ' + my1flex.dumpa(dataServ), null, true, 2);
									//fLog('--> ' + getTextOnBin(dataServ, startPos)); 
									if (res.type < 100){		
										var dd = getTextOnBin(dataServ, startPos);
									}
									//my1flex.dumpl(dd, dd);
									if (dd)
										fLog({text : dd ? dd : 'ошибка распаковки bin', bin : my1flex.dumpa(dataServ)});
								}
								
								res.from_dev = e.currentTarget == retSoc;
								stateChange(ON_DATA_END, res, dataServ); 
								dataServ = new ByteArray();
								dataServ.endian = Endian.LITTLE_ENDIAN;
							}							
							
							stateChange(ON_DATA, res, dataServ);
							
		}

		
			private function onConnect(e){
				
				 	 timConnectApp = getTimer();
					 stateChange(ON_CONNECT);
			}		
			
			
			
			//******************************formaPack
			
					



	
	/*
	 * All proto AT,BIN 
	 * 
	 */
	public function sendPack(commands/*com1;com2*/, proto, obData = null,  fWaitRecive:Function = null, waitRecive = 0, fTimeOut = null, errorCode = 0, countRequest = null){
			
			
			countRequest = countRequest == null ? def.COUNT_REQUEST_IF_NO_ANSWER : countRequest;
			waitRecive = waitRecive || def.WHIT_RECIVE;			

			//cash
			if (!is_abort && !is_server){
				var ff = function() { sendPack(commands, proto, obData, fWaitRecive, waitRecive, fTimeOut, errorCode, countRequest);	};
				requestCache.push(ff);
				return;
			}
			
			
			if (!soc.connected) return false;
					
			numRequest = countRequest;		
			//Alert.show(numRequest);
			fRequestContent = function() {	sendPack(commands, proto, obData, fWaitRecive, waitRecive, fTimeOut, errorCode, numRequest);	};	
			
			var pack, pack2;
			var res = {};
			var code = 1;
			if (is_server && obData) code = 2; 
			if (!is_server && obData) code = 3;
			if (is_server && !obData) code = 4;
			if (errorCode) code = errorCode;
			
			if (commands is Array) commands = commands.join(';');
			
			var c = commands.toString().match(/[^\;]+/g);
			
			if (proto == def.PROTO_BIN){
				
 					if (!(pack = getBinPack(commands, obData, code))) return 0;
					
					 
					if (is_server){
						pack2 = '';
						for (var i in c)	 	
							pack2 += getTextPack(c[i], obData, code) + '\n';					
							if (!pack2.match(/OK$|ERROR/m)) pack2 += '\nOK';	
						//fLog('<-- ' + pack2 + '\n', null, true, 3);
						fLog({text : pack2, bin : my1flex.dumpa(pack)} , null, true, 2);
					} else
						if (pack)
								fLog('<-- ' + my1flex.dumpa(pack) + '\n', null, true, 4);
					
					sendBuf(pack,  is_server ? null : function(bb, proto){
							switch (proto){
									case def.PROTO_TEXT :	//my1flex.dumpl(res,'vvvvvvvvvvvvvvvvvv');
														/*	fLog('--> ' + bb.toString() + '\n');		
															var ss1 = bb.toString().match(/[^\n\r]+/gm);
															var ss2 = '';
															res[1] = {};
															res[2] = {};
															//my1flex.dumpl(ss1,'vvvvvvvvvvvvvvvvvv');
															//for (var i in ss1){
															for (var i in toCommands) {
																//Alert.show(ss1[i] + '___' + ss1[i].charAt(0));	
																var sch = scheme[ss2.match(/\w+/)];
																if (sch){
																	var ind = sch.index;
																	//if (!res[ind])  res[ind] = {};
																}
																//if ((ss2 && ss1[i].charAt(0) == '+')){
																if ((ss2 && toCommands[i].charAt(0) == '+')){
																	res[ind] = extractTextPack(ss2)[ind];
																	//my1flex.dumpl(ss,'ss');
																	//Alert.show('tt__' + ss2);
																	ss2 = '';
																} 
																  //ss2 += ss1[i] + '\n\r';
																  ss2 += toCommands[i] + '\n\r';
															}
															
															res.type = obData ? 2 : 4 ;
															if (ss2) res[ind] = extractTextPack(ss2)[ind];
															//my1flex.dumpl(res,'vvvvvvvvvvvvvvvvvv');
															//Alert.show(ss2);
															*/
															var ltext = getStrFromBuf(bb);
															fLog('_--> ' + ltext + '\n');
															var ss1 = ltext.match(/[^\r\n]+/gm);
															//Alert.show(ss1.join('\n'));
												       		var res = {};
												       		var i = 0;
												       		var k = 1;
												       		var ss2 = '';
												       		
												       		for (var n=0; n<ss1.length; n++){
													       			
													       		if (ss1[n].match(/^\+|OK/i)) continue;
													       		
													       		ss2 += ss1[n] + '\r\n';
													       		
													       		var sch = scheme[c[i]];
													       		
																if (!sch) continue;
																
																var ind = sch.index;
																
																
																if (!res[ind])  res[ind] = {};
													       				
													       		//Alert.show(sch.data.count);		
													       		if (k == sch.data.count){
													       			res[ind] = extractTextPack(ss2, '+' + c[i] + '=?')[ind];
													       			//my1flex.dumpl(res);
													       			//Alert.show(ss2+'__'+c[i]);
													       			ss2 = '';
													       			i++;	
													       			k = 0;
													       		}
													       		 k++;
													       		 //Alert.show(ss1[n]);
												       		}
																	
															break;
									case def.PROTO_BIN :	
															res = extractPack(bb);
															
															var ss = getTextOnBin(bb, bb.position);
															fLog('--> ' + my1flex.dumpa(bb) + (!is_server ? '   (' + ss.toString().replace(/[\r\n]+/g,'') + ')' : '') + '\n');
															break;						
								}
						
						if (requestCache.length) requestCache.pop()();
						if (fWaitRecive) fWaitRecive(res);
							
						
					},waitRecive, fTimeOut);
			}
			
			
			if (proto == def.PROTO_TEXT) {
				
				var n = 0, k = 0, nOld;
				var mind;
				
				//my1flex.dumpl(c, c);
				//return;
				//Alert.show();
				function go() {
						
						 
						if (c[n]){
							
							
							var ind = scheme[c[n]] && scheme[c[n]].index || 0;
							if (!res[ind])  res[ind] = {};
							
							//Alert.show(n + '___' + c[n]+"__indedx=" + ind);
							//my1flex.dumpl(obData[ind], obData[ind]);
							
							if (nOld != n){
								mind = [];
								for (var i in obData && obData[ind]) mind.push(i); 
								nOld = n;
							}
							//my1flex.dumpl(mind, k);
							
							if (obData && mind){
								var obTo = {};
								obTo.hexReq = obData.hexReq;
								obTo[ind] = {};
								//my1flex.dumpl(obData, k);
								if (is_server) obTo[ind] = obData[ind];
									else {   
										//my1flex.dumpl(obData, 'do');
										//if (!obData[ind][k]) obData[ind] = {k : obData[ind]}; 
										//my1flex.dumpl(obData, 'pos');
										obTo[ind][mind[k]] = obData[ind][mind[k]];
										//my1flex.dumpl(obTo, pack);
								}
							}
							
							//Alert.show(c[n]+'__k='+k+'+_n='+n);
							if (code > 4){ 
								obTo.struct = obData.struct;
								obTo.param = obData.param;
							}
							
							pack2 = getBinPack(c[n], obTo, code); 
							pack = getTextPack(c[n], obTo, code);
							
							//Alert.show('"'+ pack+'"________'+code);
							//my1flex.dumpl(obTo, pack);
							
							
							if (is_server){
								fLog({text : pack, bin : my1flex.dumpa(pack2)} , null, true, 4);
							} else
								fLog('<-- ' + pack + '\n', null, true, 3);
							
							//Alert.show(pack);
							//return;
							
							//Alert.show(pack);
							//my1flex.dumpl(obData);
							
							var buf : ByteArray = new ByteArray();
							//buf.endian = Endian.LITTLE_ENDIAN;
							buf.writeMultiByte(pack.toString().replace(/[\r\n]+$/) + '\r\n', charSet);
							buf.position = 0;
														
							sendBuf(buf, is_server ? null : function(bb, proto){
								//Alert.show('vvvvvvvvvvvvvvvvvvvvvvvv');
								//Alert.show(my1flex.dumpa(bb));
								//return;
								switch (proto){
									case def.PROTO_TEXT :	//var rr = extractTextPack(bb.toString(), (code !=3 ? ("+" + c[n-1] + '=?') : ''));
															var ltext = getStrFromBuf(bb);
															var rr = extractTextPack(ltext, (code !=3 ? ("+" + c[n-1] + '=?') : ''));
															if (rr.type && rr.type < 5) res[ind] = rr[ind]; else res = rr;
															//res[ind] = extractTextPack(bb.toString())[ind];
															if (res.type < 5) res.type = obData ? 2 : 4;
															fLog('--> ' + ltext + '\n');
															break;
									case def.PROTO_BIN :	var rr = extractPack(bb);
															if (rr.type && rr.type < 5) res[ind] = rr[ind]; else res = rr;
															var ss = getTextOnBin(bb);
															fLog('--> ' + my1flex.dumpa(bb)  + (!is_server ? '   (' + ss.toString().replace(/[\r\n]+/g,'') + ')' : '') +  '\n');
															break;						
								}
									
								go();								   //<--
							},waitRecive, fTimeOut);
							
							//if (is_server) sendStr('\n\rOK');	
							
						} else
							if (!is_server){	
								if (requestCache.length) requestCache.pop()();
								fWaitRecive(res);
								}
						
							
					k++;
					
					//n++;
					//Alert.show(c[n] && (code == 1 || code == 2  || (obData && !obData[ind][k])));
					
					//my1flex.dumpl(obData[ind][k], k);
					//if (c[n] && (code == 1 || code == 2  || (obData && !obData[ind][k]))){
					//if (obData[ind])
						//Alert.show(obData[ind][k]);
					if (c[n] &&   (code == 1 || code == 2  ||  (!(obData && obData[ind] && obData[ind][mind[k]])))){
						//Alert.show(n + '___' + k);		
						n++;
						k = 0;		
						//if (is_server) setTimeout(go, 10);
						if (is_server) go();
					}
					
				};
				
				go();		
				
						
						
						
						//Alert.show('____' + pack);
			}
			
			
			return pack;
		}
	
	

	/*
	 * 
	 * commands = SIM_GPRS
	 * obData = 	var cc = {};
					cc[1] = {}; //index
					cc[1][1] = ['0123456789ABCDEF','0123456789ABCDEF0123456789ABCDEF','0123456789ABCDEF','0123456789ABCDEF']; //struct	
					cc[1][2] = ['0123456789ABCDEF','0123456789ABCDEF0123456789ABCDEF','0123456789ABCDEF','0123456789ABCDEF']; //struct
	 * 
	 */	
		
	public function getBinPack(commands, obData = null, code = 1) {
		
			var c = commands.toString().match(/[^\;]+/g);
			 
			var buf : ByteArray = new ByteArray();
			
			buf.endian = Endian.LITTLE_ENDIAN;
			
			buf.writeByte(0x80);
			buf.writeByte(0x80);
			buf.writeByte(0x80);
			buf.writeByte(0x01); //ver
			buf.writeShort(0);   //len first

			buf.writeByte(255);
			buf.writeByte(255);
			
			if (nPack > 0xFFFF) nPack = 1;
			buf.writeShort(nPack++); 	 	  //Номер пакета (1)
			//buf.writeShort(0xEEEE); 		  //Номер пакета (1)
			buf.writeByte(code);	 		  //Функция чтения данных из устройства(1)
			if (code > 4){
				buf.writeByte(code - 0x80);						//error proto
				buf.writeShort(obData.index); 					//Индекс команды, в которой обнаружена ошибка, 0 - поле не заполнено
				buf.writeShort(obData.struct); 					//n struct
				buf.writeByte(obData.param);
			}
			
			/*
			//error
			if (code > 100){
				for each(var p in c) {
					var cur = scheme[p];
					buf.writeShort(cur.index);	
					buf.writeShort(0);	 	
				}
			}
			*/
			
			//my1flex.dumpl(c, commands + '__' + (commands is Array));
			
			//Alert.show(c);
			
			if (code < 4)
				buf.writeByte(c.length);	  //Количество индексированных команд в пакете(1)
				
			if (code < 5)	
				for each(var p in c) {
				var cur = scheme[p];
				//Alert.show("'"+p+"'");
				//my1flex.dumpl(scheme);
				
				if (!cur){
							Alert.show('not found index command: ' + p + ' ' + parseInt(p).toString(16) + 'position buf = ' + buf.position);
							return 0;
					}	
				//my1flex.dumpl(obData[cur.index]);
				
				//Alert.show(obData[cur.index][0] is ByteArray);
				   
				var ns = 0; 	
				if (code == 1) {
					buf.writeShort(cur.index);						//Индекс команды RF_SENSOR (3)
					buf.writeShort(nStructForse);	 				//Номер запрашиваемой структуры ( 0 - все структуры )
				} else
					if (obData) {
						var all_struct = my1flex.countOb(obData[cur.index]) > 1;		
						//for each(var o in obData[cur.index]) {
						for (var k in obData[cur.index]) {
								//if (ns + 1 > cur.data.count) break;  	 	 //не больше стуктур схемы
								var o = obData[cur.index][k];			
								
							//	buf.writeShort(cur.index); 	   	   			//Индекс команды RF_SENSOR (3)
							    if (!ns || !all_struct){	
									buf.writeShort(cur.index); 	   	   					//Индекс команды RF_SENSOR (3)
									buf.writeShort(all_struct ? 0 : (k + 1));	 						//Номер запрашиваемой структуры ( 0 - все структуры )
									buf.writeShort(getLenStruct(obData[cur.index], cur, code == 3));  		//len
							    }
							    
								for (var i in o){
									if (o[i] == ',' && cur.data.struct.el[i].type.indexOf('ro') == -1){
									if (!is_server) fLog('ERROR в бинарном протоколе не должно быть пустых  параметров, данные не переданы');
										return 0;
									}
									if ((cur.data.struct.el[i].type.indexOf('ro') > -1 && code == 3)|| o[i] == ',' ) continue;
									var is_str = cur.data.struct.el[i].type.indexOf('s') > -1;
									//if (!cur.data.len[i]) break;     		 //не больше схемы
									 //writeN(buf, (o[i] ? o[i] : cur.data.struct.el[i].type.indexOf('s') > -1 ? ' ' : 0), cur.data.len[i]);
									 //if (o[i] == ',') buf.writeByte(0);
									 //	else
									 writeN(buf, o[i], cur.data.len[i], is_str); 
									//Alert.show(cur.index+'___++___' + cur.data.len[i]);
								}
							ns++;	
						}
					}
			}
			
			buf.position = 4;
			buf.writeShort(buf.length + 2);			//len + crc
			
			buf.position = buf.length;
			buf.writeShort(my1flex.getcrcB(buf));	  		  //Младший и старший байты контрольной суммы (показан условно)

			buf.position = 0;
			//Alert.show('__' + my1flex.dumpa(buf));
			nStructForse = 0;
			return buf;		
		}

		
		
		
		//************
		
		/*
		 * return [commands[structures]]
		 * 
		 */	
		public function extractPack(buf : ByteArray) {
			
			//my1flex.dumpa(buf);
			
			//var nPack = buf.readUnsignedByte();
			var res = {};
			res.commands = [];
			
			
			//check crc
			//var cpos = buf.position;
			buf.position = 0;
			buf.position += 4;   //up to len
			var lenPack = buf.readUnsignedShort();
			var crc = my1flex.getcrcB(buf, 0, lenPack - 2);
			buf.position = (lenPack - 2);  // skep 
			var crcIn = buf.readUnsignedShort();
			
			//Alert.show('len=' + lenPack + ' pos=' + buf.position + ' crc=' + crc + '__' + crcIn + '\n' + my1flex.dumpa(buf));
			
			if (crc != crcIn) {
				res.commands = ['ERROR_CRC']; 
				fLog('--> ERROR CRC PACK'); 
				res.type = 210;
				return res;
			}
			buf.position = 0;
			//

			
			buf.position += 8;	 			 			//n pack
			
			var  npack = buf.readUnsignedShort();
			if (is_server) nPack = npack;
			//var code = buf.readUnsignedByte();
			//Alert.show(my1flex.dumpa(buf));
			//Alert.show(buf.position);
			var code = buf.readUnsignedByte();
			//Alert.show(buf.position+'___' + code);
			res.type = code; 
			
			//if ((code & (1 << 7)) != 0){
			if (code > 100) {
				//error
				//Alert.show('error code: ' + code);
				//return res;	
			}
			
			if (code == 210) {
				fLog('--> ERROR CRC PACK ON SERVER');
				return res;
			}
			
			
			var nCom = buf.readUnsignedByte();
			var i = 0;
			var oldIndex, len;
			//var cum = 0;
			var newLine = true;
			while (buf.bytesAvailable > 2) {
				
				//80 80 80 01 1C 00 FF FF EE EE 03 01   0100 0100 0800   31 00 31 00 31 00 31 00 A2 2B 
				//80 80 80 01 2C 00 FF FF EE EE 03 02   0100 0000 1000   31 00 31 00 31 00 31 00 32 00 32 00 32 00 32 00   0200 0000 0200   01 0A AA 75 

				if (newLine) {
					
						var indexCom = buf.readUnsignedShort(); 		//Индекс команды, которой запрашивались данные
						if (oldIndex != indexCom) { 
							var cur = getComObjByIndex(indexCom);  		//по индексу команды
							//Alert.show('_____' + cur.name);
								if (!cur){
								fLog('not found index command: ' + indexCom + ' ' + indexCom.toString(16) + 'position buf = ' + buf.position);
								res.type = 0x81;
								return res;
							}
							i = 0;
							//my1flex.dumpl(res);
							res.commands.push(cur.name);
						}
					
						oldIndex = indexCom;
					  
						//var nStruct =  buf.readUnsignedShort() || i;			//Номер структуры, от которой возвращаются данные
						var tt;
						var nStruct = tt = buf.readUnsignedShort();
						if (nStruct) nStruct--; 
						
				}
				
							
						
						if (!res[indexCom]) res[indexCom] = {};
						res[indexCom][nStruct] = new Array();
						
						if (cur && code == 1 && tt == 0)
							for (var n = 0; n<cur.data.count; n++) res[indexCom][n] = {}; 
								
							
				if (code != 1){                             //если не запрос на чтение 
							if (newLine){
								len = buf.readUnsignedShort();
							/*	
								Alert.show(len);
								if (len > cur.data.len.length){
									res.type = 0x83; 
									return res;
								}*/
							}
							//Alert.show(my1flex.dumpa(buf), buf.position);
							for (var n=0; n<cur.data.len.length; n++){
									if (cur.data.struct.el[n].type.indexOf('ro') > -1 && code == 3) continue;
									var is_str = cur.data.struct.el[n].type.indexOf('s') > -1; 
									var li = readN(buf, cur.data.len[n], is_str, len);
									//if (li is ByteArray) res.is_data_bin = true;
									//res[indexCom][nStruct].push(li);
									res[indexCom][nStruct][n] = li;
									if (li is ByteArray) break;
									//cum += is_str ? li.length : cur.data.len[n]; 
									//Alert.show(cur.name+' '+cur.data.len[n]);
							}
						}
				//Alert.show(newLine);		
				i++;		
				newLine = i == cur.data.count;
				nStruct++;
			}  
			//Alert.show(buf.position + '\n' + my1flex.dumpa(buf));
			//my1flex.dumpl(res, 'ssssssssss');
			return res;		
		}
	
	
	//***************************************************text proto
	
	
	public function getTextPack(command, obData = null, code = 1) {
		
		
			//my1flex.dumpl(obData);
			
			if (code == 4){
				return 'OK';
			}
			
			if (code > 4){
				//my1flex.dumpl(obData);
				return 'ERROR ' + (code - 0x80) + (obData && obData.param ? ' ' + obData.param  : '');
			}
			if (command.toString().match(/(?<=\=)[\d\-]+(?=\,)/)) return command;
			
			
			//pack request n
			
			
			
			
		    command = command.toString().match(/\w+/);
		    
			var cur = scheme[command];
			if (!cur){
				//Alert.show('Не определена команда ' + command);
				fLog('--> ' + 'Не определена команда ' + command);
				return;
			}
			
			
			var zz = '';
			if (obData){		
				var nStruct = my1flex.countOb(obData[cur.index]);
				
				
				for (var vv in obData[cur.index]);
				//my1flex.dumpl(obData, 'all');
				//my1flex.dumpl(obData[cur.index], 'index ' + cur.index);	
				if (nStruct != cur.data.count || code == 3) zz = (vv + 1) + ','; 
				//zz = (vv + 1) + ',';
				
				if (nStruct > cur.data.count){
					//Alert.show('Структур больше чем в описании ' + count + ':' +cur.data.count);
					fLog('warning : Структур больше чем в описании ' + nStruct + '>' +cur.data.count);
					return;	
				}
			}
			
			var res = '';
			//my1flex.dumpl(obData[cur.index]);
			var count = 1;
			
			var cc = '+' + command + '=' + zz + (code != 3 ? '?\r\n' : '');
			
			if (code == 1 || code !=2 && !obData) res = cc;
				
			
			for (var n in  obData && obData[cur.index]) {
				
			//for (var n = 0;  n<cur.data.count; n++) {
				if (count > cur.data.count) break;  	  //не больше стуктур схемы
				
				if (code == 3) res += '+' + command + '=' + (n + 1) + ','; 
				
				var type;
				for (var i in obData[cur.index][n]){
					
						
						//Alert.show(obData[cur.index][n][i]);
						//if (!cur.data.len[i] || code == 1) break;      //не больше елементов схемы
						if (code == 1) break;      //не больше елементов схемы
						
						if (i in cur.data.struct.el) type = cur.data.struct.el[i].type;
						var ss = '';
						var lin = obData[cur.index][n][i];
						if (obData[cur.index][n][i] != ','){  
							if (lin is ByteArray)
								ss = '[bin_data : len ' + lin.length + ']';
								else 
									ss = type.indexOf('s') > -1 ? '"' + lin+ '"' : lin;
						} 
						if (obData.hexReq && type.indexOf('d') > -1) ss = '0x' + parseInt(ss).toString(16).toUpperCase();
						//Alert.show(ss+'__'+obData.hexReq);
						//res += (type && type.indexOf('ro') > -1 ? '' : ss) + ',';
						res +=  ss + ',';
				}
				//res = res.replace(/[,]+$/,'');
				res += '\r\n';
			 count++;	
			}
			//Alert.show('++'+res);
			return res.replace(/[\r\n,]+$/,'');
		
	}
		
		
		
		
	public function extractTextPack(s, commandP = ''){
		
			var res = {};
			res.type = 1; 
			
			
			
			//Alert.show("'"+s+"'");
			
			if (s == 'OK' || s.toString().match(/^\r\nOK[\r\n]+/)){
				res.type = 2;
				return res;		
			}
			
			if (s.match(/^ERROR/)){
				//Alert.show('___' + s);
				res.type = s.match(/\d+/)[0]  || 0;
				res.type = parseInt(res.type) + 0x80;
				res.mes = s.toString().match(/(?<=\d)\s+\d/) || '';
				return res;		
			}
			
			s = s.replace(/[\n\r]*OK[\n\r]+$/i,'');
			
			//s = s.replace(/(?<=\,)\s+|\s+(?=\,)/g, '');
			//Alert.show(s);
			 
			if (commandP) s = commandP + '\r\n' + s; 		
					
			var command =  s.match(/\w+/);
			
			
			//var command = s.match(/^\+\w+\=(?:\?|\d)/) ?  s.match(/\w+/) :  commandP;    //проверка вкл команды в пакет
			
			//Alert.show("'"+command+"'");
			var cur = scheme[command];
			
			res.commands = [command];
			
			if (!cur){
					//Alert.show('Не определена команда ' + command);
					//Alert.show(s+'________' + command);
					res.type = 0x81;
					return res;
			}
			
			res.index = cur.index; 
			
			//var el = s.match(/[^\,\r\n\?]+/g);
			
			var isReq = s.match(/\?\w?$/gm);
			
			
				
			var structs = s.match(/[^\r\n]+/g);
			//var nStructs = s.match(/(?<=\=)[\d\-]+(?=\,)/);
			var nStructs = parseInt(s.match(/(?<=\=)[\s\d\-]+(?=\,)/));
			
			//nStructs = parseInt('ss');
			//Alert.show(structs + '___________' + nStructs + '__' + (nStructs ? 1 : 0));
			
			res.hexReq = s.match(/h$/);
			
			res.nStructs = nStructs; 
			
			//Alert.show(!(isReq.length || nStructs) + '____'+  isReq.length  + '++++++' +nStructs);
			if (!(isReq.length || nStructs) ){
					//Alert.show(s+'____2____');
					res.type = 0x85;
					return res;
			}
			
			
			//Alert.show(s + '_________________________'  + nStructs);
			
			if (!res[cur.index]) res[cur.index] = {};
			
			//var parW = structs[0] && structs[0].match(/(?<=\,)[^\,\?]+|(?<=\,)\,/g);
			//var parW = structs[0] && structs[0].match(/\".*?\"|(?<=\,)[^\,\?\s]+|(?<=\,)\,/g);
			//var parW = structs[0] && structs[0].match(/\".*?[\"]+|(?<=\,)[^\,\?\s]+|(?<=\,)\,/g);
			//var parW = structs[0] && structs[0].match(/\".*?\"|[^\,\s\?]+|(?<=\,)\,/g).slice(1);
			var parW = structs[0] && structs[0].match(/^[\w+\=\s]+|\".*?\"|[^\,\s\?]+|(?<=\,)\,/g).slice(1);
			if (parW && parW.length && structs[0] && structs[0].match(/\,\??$/)) parW.push(',');
			
			if (structs[0].match(/\?h?$/)) parW = []; 
			//Alert.show(parW + '__' +structs[0]);
			//Alert.show(structs.join('_') + '___' + structs.length);
			//Alert.show(parW.join('_') + '___' + parW.length); 
			
			//for (var n = 0; n<cur.data.count; n++) {
			//var ll = (structs.length > 1 || parW) ? structs.length : cur.data.count;  
			var ll = cur.data.count;
			if (parW && parW.length) ll = 1;

			for (var n = 0; n<ll; n++) {
					var ind = nStructs ? nStructs - 1 : n; 
					//Alert.show(ind);
					
					if ((ind > cur.data.count - 1) || (ind < 0)){
						res.type = 0x82;
						return res;
					}
					
					if (!res[cur.index][ind]) res[cur.index][ind] = [];
					
					var par =  (structs[n+1] && structs[n+1].match(/[^\,]+/g)) || parW;
					
					//Alert.show(par + '____' + cur.data.len.length);
					
					if (!isReq.length && (par.length != cur.data.len.length)){
							//fLog('warning : Параметров бол');
							res.type = 0x83;
							//Alert.show('e0');
							//return res;
					}
					 
					for (var i = 0; i < cur.data.len.length || i < par.length;  i++) {
						//Alert.show(par); 
						var curDataLen;
						var type;
						if (par && par[i]){
							//Alert.show('wwwwwww');
							//Alert.show(par[i]);
							 if (i in cur.data.len) curDataLen = cur.data.len[i];
							 if (i in cur.data.struct.el) type = cur.data.struct.el[i].type;
							 
							 var errCode = checkValue(par[i], type, curDataLen, !isReq.length);
							 if (par[i] == ',') res.someReadOnly = true; 
							 var str = par[i].match(/(?<=\").*(?=\")/);
							 var hexParam = par[i].match(/0x[\da-fA-f]{1,2}/);
							 if (errCode > 100){
							 	res.type = errCode;
							 	res.mes = i + 1;
							 	//Alert.show('e');
							 	//return res;
							 }
							 if (res.type < 100) res.type = is_server ? 3 : 2; 					 // 0x02 - функция подтверждения чтения структуры параметров;  0x03 - функция записи структуры параметров;
							 //Alert.show(hexParam + '_______' + parseInt(hexParam));
							 res[cur.index][ind].push(str ? str[0] : hexParam ? parseInt(hexParam) : type.indexOf('d') > -1 ? parseInt(par[i]) : par[i]);
						}
					}
				}
		//my1flex.dumpl(res);	
		return res;
		}
		
		
		
			
	//********************************utils
	
	private function checkValue(value, type, len, isWrite){
		var code = 0;
		if (type){
			var is_d = type.indexOf('d') > -1;
			var is_s = type.indexOf('s') > -1;
			var is_ro = type.indexOf('ro') > -1;
			var is_hex = value.toString().match(/0x[\da-fA-f]{1,2}/); 
			
			//Alert.show(value+'________'+is_hex);
			
			if (isWrite && is_ro && value != ',') code = 0x86;
			if (!is_ro && value!= ','){
			if ((is_d && (value >= Math.pow(2, 8*len)  )) || (is_s && value.length - 2 > len)) code = 0x85;
			if ((is_d && value.toString().match(/[^\d\-\,]/) && !is_hex) || 
				  	(is_s && !value.match(/^\".*\"$/))) code = 0x84;
				  	
			}
		}	
		return code; 
	}
	
	public function getComObjByIndex(index){
		var s:String;
			for (var i in scheme)
					if (scheme[i].index == index){ 
						scheme[i].name = i;
						return scheme[i];
					} 
		
		return null;			
	}

	
	private function readN(buf:ByteArray, len, is_str, lenStruct){
		
			var res;
			
			if (is_str){
				var aa:ByteArray = new ByteArray();
					  while (buf.bytesAvailable && (res = buf.readUnsignedByte())!= 0)
					 		if (res) aa.writeByte(res);
					  res = getStrFromBuf(aa);	
			} else {
			
				switch (len){
					
				case 1 : if (buf.bytesAvailable > 0) res = buf.readUnsignedByte();
						 break;	 			
				case 2 : if (buf.bytesAvailable > 1) res = buf.readUnsignedShort();
						 break;
				case 4 : if (buf.bytesAvailable > 3) res = buf.readUnsignedInt();
						 break;
						 
				default :	res = new ByteArray();
							//Alert.show(buf.bytesAvailable);
							buf.readBytes(res, 0, Math.min(lenStruct, buf.bytesAvailable));
				}				
		}
		return res;	
	}
	
	
	private function writeN(buf:ByteArray, data, len, is_str){
		
			
			if (is_str){
				  	buf.writeMultiByte(data, charSet);
					buf.writeByte(0);	
			} else {	
				
					
				switch (len){
					
				case 1 : buf.writeByte(data);
						 break;	 			
				case 2 : buf.writeShort(data);
						 break;
				case 4 : buf.writeUnsignedInt(data);
						 break;
				 		
				default :buf.writeBytes(data);
						 break;		 		 	
				}	
		  }
	}
	

	private function getLenStruct(st, cur, skipRo = false){
		var res = 0;
		var sType;
		//my1flex.dumpl(cur);
		for each(var p in st){
			for (var i in p){
				var oo = i;
			if (!(oo in cur.data.struct.el)) sType = true;
				else sType = (cur.data.struct.el[i].type.indexOf('s') > -1);
				if (cur.data.struct.el[i].type && cur.data.struct.el[i].type.indexOf('ro') > -1 && skipRo) continue;
				res += sType ? p[i].toString().length + 1 : cur.data.len[i] > 4 ? p[i].length /*bytearray*/ : cur.data.len[i]; 
			}
		}
		//Alert.show('__' + res);
		return res;	
	}
	
	private function summ(m):uint{
		var res = 0;
		for each(var p in m) res += p;
		return res;
	}
	
	private function strFill(s, len, chFill = ' '){
					for (var i = s.length; i<len; i++) s += chFill;				
					return s;
			}
		
			
	private function getBinOnText(s, code, commandP = ''){
		
		//Alert.show(commandP+'____________________');
		var res = extractTextPack(s, commandP);
		
		//my1flex.dumpl(res, 'xxxx____'+ s);
		if (res.someReadOnly) return false;
		
		var command =  commandP && commandP.toString().match(/\w+/) || s.toString().match(/\w+/);
			nStructForse = 0 || s.toString().match(/(?<=\=)[\d\-]+(?=\,)/);
			//Alert.show(nStructForse + '______' + s);
			//Alert.show(command + '___' + code);
			//my1flex.dumpl(res, 'xxxx____'+ command);
			return getBinPack(command, res, code);
		 				
	}
	
	private function getTextOnBin(buf, pos = 0){
		buf.position = pos;
		var res = extractPack(buf);
		//my1flex.dumpl(res);
		var s = '';
		if (res.type == 4){
			s = 'OK';
		}
		if (res.type > 4){
			s = 'ERROR ' + (res.type - 0x80);
			return s;
		}
		
		for (var i in res.commands){	
			//Alert.show(p);	
			var ind = scheme[res.commands[i]].index;
			var rr = {}; 
			//if (res[ind] is ByteArray) rr[ind] = '-bin_data- : len ' + res[ind].length;
				//else  rr[ind] = res[ind];
			rr[ind] = res[ind];	
			//my1flex.dumpl(res, ind );
			s += getTextPack(res.commands[i], rr, res.type) + '\n';
		}
		return s;
		 				
	}
	
	private function getStrFromBuf(buf, len = 0){
				var n = buf.position;
				buf.position = 0;
				var res = buf.readMultiByte(len || buf.bytesAvailable, charSet);	
				buf.position = n;
				return res;
			}
			
			
	}
}
